#include "objmanager.h"
#include "engine.h"
#include "common.h"
#include "engine.h"
#include <vector>

void obj_manager::add_obj(object *toadd)
{
    objs.push_back(toadd);
    is_gpushed.push_back(false);
    //if(!toadd->is_tex_loaded&&toadd->is_textured){
    //    toadd->texture_load();
    //}
    //tex.push_back(toadd->)

}

void obj_manager::rem_obj(object *toremove)
{

    std::list<object*>::iterator it=objs.begin();
    std::list<bool>::iterator it1=is_gpushed.begin();
    for(; it!=objs.end(); it++, it1++)
    {
        if((*it)==toremove)
        {
            break;
        }

    }
    objs.erase(it);
    is_gpushed.erase(it1);

}

void obj_manager::push_objects()  ///asynchronously allocates and swaps triangle buffer for new buffer
{

    unsigned int trianglestoallocate=0;
    bool regalloc=false;

    std::list<object*>::iterator it=objs.begin();

    //std::cout << "hi" << std::endl;

    for(std::list<bool>::iterator it1=is_gpushed.begin(); it1!=is_gpushed.end(); it1++, it++)
    {


        if((*it1)==false)
        {

            regalloc=true;

        }
        (*it1)=true;

        trianglestoallocate+=(*it)->max_tnum;



    }


    cl_float4 *tstuff=new cl_float4[trianglestoallocate * 12];


    unsigned int runningtotal=0;

    //std::cout << objs.size() << std::endl;

    //for(int i=0; i<max_tnum; i++){
    for(std::list<object*>::iterator it=objs.begin(); it!=objs.end(); it++)
    {
        //std::cout << (*it)->curtriangle << std::endl;
        //std::cout << trianglestoallocate << std::endl;
        for(unsigned int i=runningtotal; i<(*it)->curtriangle+runningtotal; i++)
        {
            triangle *P=(NULL);
            //std::cout << P->num_tri << std::endl;
            //std::cout << i << std::endl;
            if((*it)->base==0)
            {
                //P=&T->get_triangle(i);
                P=&((*it)->triangles[i-runningtotal]);
            }
            else
            {
                exit(1212321);
            }


            for(int j=0; j<3; j++)
            {
                tstuff[i*12 + j].x=P->points[j].pos.x;
                tstuff[i*12 + j].y=P->points[j].pos.y;
                tstuff[i*12 + j].z=P->points[j].pos.z;
                // std::cout << "2";
            }
            for(int j=3; j<6; j++)
            {
                tstuff[i*12 + j].x=P->points[j-3].normal.x;
                tstuff[i*12 + j].y=P->points[j-3].normal.y;
                tstuff[i*12 + j].z=P->points[j-3].normal.z;
                // std::cout << "3";
            }
            for(int j=6; j<9; j++)
            {
                tstuff[i*12 + j].x=P->points[j-6].col.r;
                tstuff[i*12 + j].y=P->points[j-6].col.g;
                tstuff[i*12 + j].z=P->points[j-6].col.b;
                // std::cout << "4";
            }
            for(int j=9; j<12; j++)
            {
                tstuff[i*12 + j].x=P->points[j-9].uvw.x;
                tstuff[i*12 + j].y=P->points[j-9].uvw.y;
                tstuff[i*12 + j].z=P->points[j-9].uvw.z;
                // std::cout << "5";
            }
        }
        //  std::cout << "hello";
        runningtotal+=(*it)->curtriangle;

    }







    //std::cout << "end";

    //std::flush(std::cout);

    ///object is passed with texture information. Collate here. DO IT
    ///assume all objects have textures for now. If istextured set to false, use gray texture?
    ///have this collapse and sort the gids in objects to prevent blank texture bits

    cl_image_format fermat;
    fermat.image_channel_order=CL_RGBA;
    fermat.image_channel_data_type=CL_FLOAT;

    cl_mem gtex=clCreateImage3D(cl::context, CL_MEM_READ_ONLY , &fermat, 1024, 1024, objs.size(), 0, 0, NULL, &cl::error);

    if(cl::error!=0)
    {
        std::cout << "Fatal error: Failed to allocate gmemory (objmanager.cpp)" << std::endl;
        exit(cl::error);
    }

    size_t row_pitch=(1024*sizeof(cl_float4)); ///imagewidth
    size_t slice_pitch=(1024*row_pitch); ///imageheight

    size_t *prow_pitch=&row_pitch;
    size_t *pslice_pitch=&slice_pitch;

    size_t origin[3]= {0,0,0}, region[3]= {1024, 1024, objs.size()};


    cl_float4 *imagemap=(cl_float4*)clEnqueueMapImage(cl::cqueue, gtex, CL_TRUE, CL_MAP_WRITE, origin, region, prow_pitch, pslice_pitch, 0, NULL, NULL, &cl::error);

    if(cl::error!=0)
    {
        std::cout << "Fatal error: Enqueuemapimage (objmanager.cpp)" << std::endl;
        exit(cl::error);
    }


    it=objs.begin();
    for(int k=0; k<objs.size(); k++, it++)
    {

        for(int i=0; i<1024; i++)
        {

            for(int j=0; j<1024; j++)  ///height
            {

                imagemap[(i + 1024*j) + 1024*1024*k]=(*it)->texture[i + (*it)->tex_width*j];

            }

        }

    }


    //std::cout << "hi";


    cl_uint *imsuretheresabettersolutionthanthis=new cl_uint[trianglestoallocate];


    cl_mem gtransitionmem=clCreateBuffer(cl::context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(cl_float4)*trianglestoallocate*12, (tstuff), &cl::error);
    cl_mem gtransitionisdrawbuffer=clCreateBuffer(cl::context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, sizeof(cl_uint)*trianglestoallocate, imsuretheresabettersolutionthanthis, &cl::error); ///need to sort out textures and mark triangle beginnings
    cl_mem gtransitionatomic=clCreateBuffer(cl::context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, sizeof(cl_uint)*trianglestoallocate, (imsuretheresabettersolutionthanthis), &cl::error);
    cl_mem tempfree;
    cl_mem tempfree1;
    cl_mem tempfreeimage;
    cl_mem tempfreeatomic;

    //Engine::gid_bufferisread=new cl_uint[trianglestoallocate];
    //Engine::gid_bufferiswritten=new cl_uint[trianglestoallocate];

    cl_uint *transitiongidread=new cl_uint[trianglestoallocate];
    cl_uint *transitiongidwrite=new cl_uint[trianglestoallocate];
    cl_uint *transitionabufread=new cl_uint[trianglestoallocate];
    cl_uint *freeme1;
    cl_uint *freeme2;
    cl_uint *freeme3;
    gmemory_mutex.lock();
    tempfree=Engine::gtriangles;
    tempfree1=Engine::gisdrawbuffer;
    tempfreeimage=Engine::image3d;
    freeme1=Engine::gid_bufferisread;
    freeme2=Engine::gid_bufferiswritten;
    freeme2=Engine::atomic_buffer_read;
    tempfreeatomic=Engine::atomic_id_buffer;
    Engine::gtriangles=gtransitionmem;
    Engine::gisdrawbuffer=gtransitionisdrawbuffer;
    Engine::itriangles=trianglestoallocate;
    Engine::image3d=gtex;
    Engine::gid_bufferisread=transitiongidread;
    Engine::gid_bufferiswritten=transitiongidwrite;
    Engine::atomic_id_buffer=gtransitionatomic;
    Engine::atomic_buffer_read=transitionabufread;
    gmemory_mutex.unlock();
    clReleaseMemObject(tempfree);
    clReleaseMemObject(tempfree1);
    clReleaseMemObject(tempfreeimage);
    clReleaseMemObject(tempfreeatomic);
    delete [] imsuretheresabettersolutionthanthis;
    delete [] tstuff;
    delete [] freeme1;
    delete [] freeme2;
    delete [] freeme3;
    clEnqueueUnmapMemObject(cl::cqueue, gtex, imagemap, 0, NULL, NULL);




}
